// splitter.h: interface for the CPdfSplitter class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_PDFREFINER_H__E96D58A4_632B_4894_A643_F8CA7DA429E2__INCLUDED_)
#define AFX_PDFREFINER_H__E96D58A4_632B_4894_A643_F8CA7DA429E2__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <AFXTEMPL.H>
#include "PdfToolsDefs.h"
#include "RSA.h"
#include <vector>

struct _reftable
{
	DWORD dwOffset;
	INT   dwFirstObjID;
	INT   dwObjIDCount;
	BOOL  bFirst;	// deprecated
	std::vector<DWORD> arOffsets;
};

struct _object
{
	INT		id;
	INT		gen;
	DWORD	offset;
	CString enabled;
	CString mediabox;	// for page objects in PDF v1.2
	UINT	parent;		// for page objects
	UINT	count;		// for pages object
	INT		rotate;		// for page object

	//=====================================================================
	//	Added by Vladimir Zankin [14/7/2006]
	BOOL	cached;
	INT		cached_id;
	INT		cached_gen;
	//
	//=====================================================================
	INT		objType;

	_object() : id(0), gen(0), offset(0), enabled("n"), parent(0), cached(FALSE), objType(otOther), count(0) {}
	enum
	{
		otOther, otFont, otImage, otStream, otPages, otPage,
	};
};

//=====================================================================
//	Added by Vladimir Zankin [13/7/2006]
struct _image
{
	ULONG	width;
	ULONG	height;
	BYTE	checksum[16];
	BOOL	is_xobject;
	INT		id;
	INT		gen;

	bool	operator ==(const _image& img) const
	{
		return ((width == img.width) && (height == img.height) && !memcmp(checksum, img.checksum, 16));
	}
};

struct _font
{
	CHAR	name[256];
	CString sEncoding;
	CString sWidths;
	INT		id;
	INT		gen;

	bool	operator ==(const _font& fnt) const { return (!strcmp(name, fnt.name) && sEncoding == fnt.sEncoding && sWidths == fnt.sWidths); }

};
//
//=====================================================================
struct _stream
{
	INT		m_nID;
	INT		m_nGen;
	ULONG	m_ulLength;
	CString	m_sFilter;
	BYTE	m_sChecksum[16];
	BOOL	m_bBrokenLength;

	bool	operator ==(const _stream& str) const { return m_ulLength == str.m_ulLength && m_sFilter == str.m_sFilter && !memcmp(m_sChecksum, str.m_sChecksum, 16); }
};

//////////////////////////////////////////////////////////////////////////
//	class CPdfSplitter
//////////////////////////////////////////////////////////////////////////

class DLL_SPEC CPdfSplitter  
{
public:
	CPdfSplitter();
	virtual ~CPdfSplitter();

public:
	BOOL		OpenPdf(const CString &filename, const CString &userPassword = "", BOOL bCacheFontsImages=TRUE);
	BOOL		SavePagesToFile(const CString &filename, CArray<INT, INT> *pArPageNums, HWND hProgressBar = NULL);
	INT			GetPageCount() const;
	BOOL		ClosePdf();

	//////////////////////////////////////////////////////////////////////////
	// Added By Vladimir Zankin [4/4/2006]
	BOOL		Join2Pdf(const CString &file1,		// input pdf1 filename
						 const CString &pass1,		
						 const CString &file2,		// input pdf2 filename
						 const CString &pass2,
						 const CString &output);	// output pdf filename

	BOOL		AddPagesFromFile(const CString &filename, const CString& password = "");
	BOOL		WriteDocFooter();
	//
	//////////////////////////////////////////////////////////////////////////

	//=====================================================================
	//	Added by Vladimir Zankin [13/7/2006]
	void		CacheImages();
	void		CacheFonts();
	//
	//=====================================================================


	CString		GetLastError()			{ return m_sLastError; }
	BOOL		IsPdfBroken() const		{ return m_bPdfBroken;	}
	BOOL		IsPdfLandscape() const;

private:
	HANDLE		m_hInFile;
	HANDLE		m_hOutFile;

	CArray<_reftable, _reftable>	m_arRefTables;
	CArray<_object, _object>		m_arPdfPages;
	CArray<_object, _object>		m_arPdfObjects;
	CArray<_object, _object>		m_arInserted;

	//=====================================================================
	//	Added by Vladimir Zankin [13/7/2006]
	CArray<_image, _image>			m_arImgCache;
	CArray<_font, _font>			m_arFntCache;
	//
	//=====================================================================
	CArray<_stream, _stream>		m_arStreamCache;

	INT			m_nRootId;					// catalog id
	INT			m_nPageRoot;				// new page parent
	BOOL		m_nEncryptId;				// encrypt dictionary id
	BOOL		m_bPdfBroken;
	INT			m_nMaxID;
	
	RSA::_encrypt	m_Encrypt;				// original file encryption key
	RSA::_encrypt   m_Encrypt2;				// new file encryption key (sets flags that allowes printing and removes user password)

	CString		m_sPdfVersion;
	CString		m_sLastError;
	CString		m_sUserPassword;

private:
	void		GetPdfVersion();
	void		GetXRefTables();
	void		FixXRefTables();
	void		GetPageTree();
	void		GetEncryptKey();
	CString		GetMediaBox();
	INT			GetRotate();
	void		GetObjects(int obj_id, int obj_gen);						// Get all objects that used by current
	int			CopyObject(const _object &old_object);						// copy object to new file, return new id
	void		ReplaceIds(LPBYTE &pBuffer, INT &nBufSize);					// replace obj ids with new values
	void		ReplaceDirEntry(LPBYTE &pBuffer, INT &nBufSize, const CString &key, const CString &newValue);
	void		DecryptObject(int num, int gen, PBYTE& buf, int& buflen);	// decrypt streams & strings

	BOOL		GoToLable(const CString &lable, const CString &sEndLable = pdfEndObj);
	BOOL		GoToObject(int obj_id);
	void		GetPages(int nTreeNodeID, CString mediabox, INT rotate);

	//=====================================================================
	//	Added by Vladimir Zankin [13/7/2006]
	void		CacheImage(int obj_id, int obj_gen, CArray<_image, _image> &cache);
	_image		GetImage(int obj_id, int obj_gen);

	void		CacheFont(int obj_id, int obj_gen);
	_font		GetFont(int obj_id, int obj_gen);
	//
	//=====================================================================

	UINT		GetMaxID();

	//////////////////////////////////////////////////////////////////////////
	// file IO routines
	// ---> Write to m_hOutFile <---
	void		WriteStr(CString str);
	void		WriteStrF(CString str, ...);
	void		WriteBytes(LPBYTE pBuffer, INT nBufSize);
	void		WritePagesObj(UINT nID, CArray <INT, INT> *pPages);

	// ---> Read from m_hInFile <---
	int			ReadNumR();
	int			ReadNum();
	CString		ReadString();	// return string from curren pointer pos to next '\r' or '\n' or EOF
	CString		ReadToken();	// return string from curren pointer pos to next ' ' or '\r' or '\n' or EOF
	void		ReadBytes(LPBYTE pBuffer, INT nBufSize);
	CString		ReadArray();
	void		ReadXRefTable();
	void		ReadTrailer();
	int			SkipSpaces();	// return count of skipped spaces
	void		SkipDelim();
	void		SkipBytes(int num);


	// ---> Input file pointer stacks <---
	void		PushPtr();
	void		PopPtr();

	CArray<DWORD, DWORD>	m_ptrStack;
	//
	//////////////////////////////////////////////////////////////////////////
	void		CacheFontsImages();
	void		GetChildObjects(_object &curobject, CString &line);
	void		GetPagesResources(DWORD &dwPagesResBegin, DWORD &dwPagesResLen, BOOL bWithRef=TRUE);
	void		CopyPagesResources(DWORD dwPagesResBegin, DWORD dwPagesResLen, BOOL bWithRef=TRUE);
	_stream		GetStream(int obj_id, int obj_gen);
};

#endif // !defined(AFX_PDFREFINER_H__E96D58A4_632B_4894_A643_F8CA7DA429E2__INCLUDED_)
